package com.xunyin.douyin;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xunyin.douyin.result.DouyinCouponPrepareResult;
import com.xunyin.douyin.result.DouyinCouponVerifyResult;
import com.xunyin.douyin.result.VerifyResult;
import com.xunyin.enums.CouponTypeEnum;
import com.xunyin.modules.couponnew.domain.MtCoupon;
import com.xunyin.modules.couponnew.service.UserCouponService;
import com.xunyin.modules.couponnew.service.mapper.MtCouponMapper;
import com.xunyin.modules.mtstore.domain.MtStore;
import com.xunyin.modules.mtstore.service.StoreService;
import com.xunyin.utils.DateUtil;
import com.xunyin.utils.RedisUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 抖音团购券相关接口
 * <p>
 * Created by xunyinyunshang
 * CopyRight 讯音云商 https://www.tonetn.com
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class DouyinConponServiceImpl implements DouyinConponService {

    @Autowired
    private StoreService storeService;

    @Autowired
    private RedisUtils redisUtils;

    public final static String DOUYIN_SHOP_TOKEN_INFOR = "DOUYIN_SHOP_TOKEN_INFOR";

    @Autowired
    private MtCouponMapper mtCouponMapper;

    @Autowired
    private UserCouponService userCouponService;

    /**
     * client
     */
    private static OkHttpClient OKHTTPCLIENT;

    public String getClientToken(Integer storeId) throws IOException {
        //正式环境：https://open.douyin.com/oauth/client_token/
        //沙盒环境：https://open-sandbox.douyin.com/oauth/client_token/
        String url = "https://open.douyin.com/oauth/client_token/";
        MtStore mtStore = storeService.queryStoreById(storeId);
        String accessToken = "";
        if (mtStore != null) {
            if (mtStore.getClientKey() != null && mtStore.getClientSecret() != null) {
                DouyinTokenResult tokenResult = (DouyinTokenResult) redisUtils.get(DOUYIN_SHOP_TOKEN_INFOR + storeId);
                if (tokenResult != null) {
                    Date endDate = tokenResult.getEndDate();
                    long now = (new Date()).getTime();
                    long endTime = endDate.getTime();
                    long timeDiff = (endTime - now) / 1000 / 60;
                    if (timeDiff <= 0) {
                        accessToken = setDouyinToken(url, mtStore);
                    } else {
                        accessToken = tokenResult.getAccessToken();
                    }
                } else {
                    accessToken = setDouyinToken(url, mtStore);
                }
            }
        }
        log.info("log getClientToken, accessToken=" + accessToken);
        return accessToken;
    }

    public String setDouyinToken(String url, MtStore mtStore) throws IOException {
        String accessToken = "";
        Map<String, String> map = new HashMap<>(3);
        map.put("client_key", mtStore.getClientKey());
        map.put("client_secret", mtStore.getClientSecret());
        map.put("grant_type", "client_credential");
        String str = postClientToken(url, map);
        JSONObject jsonStr = JSONObject.parseObject(str);
        JSONObject dataObject = (JSONObject) jsonStr.get("data");
        Integer errorCode = dataObject.getInteger("error_code");
        if (errorCode == 0) {
            accessToken = dataObject.getString("access_token");
            String expiresIn = dataObject.getString("expires_in");
            Date endDate = DateUtil.addDate(new Date(), Calendar.SECOND, Integer.valueOf(expiresIn));
            DouyinTokenResult douyinTokenResult = new DouyinTokenResult();
            douyinTokenResult.setAccessToken(accessToken);
            douyinTokenResult.setEndDate(endDate);
            douyinTokenResult.setStoreId(mtStore.getId());
            redisUtils.set(DOUYIN_SHOP_TOKEN_INFOR + mtStore.getId(), douyinTokenResult);
        }
        return accessToken;
    }

    public String postClientToken(String url, Map<String, String> param) throws IOException {

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS) // 超时设置
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        String resultStr = "";
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.addHeader("Content-Type", "multipart/form-data");
        FormBody.Builder builder = new FormBody.Builder();
        for (String key : param.keySet()) {
            builder.add(key, param.get(key));
        }
        Request request = requestBuilder.post(builder.build()).url(url).build();
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        resultStr = Objects.requireNonNull(response.body()).string();
        log.info("okhttp post请求结果. url：{} param：{} result:{}", url, param, resultStr);
        return resultStr;
    }

    public DouyinCouponPrepareResult prepareCertificate(String code, String encryptedData, String clientToken) throws UnsupportedEncodingException {
        String str = getDataSynFromNet(code, encryptedData, clientToken);
        log.info("log getDataSynFromNet, str=" + str);
        JSONObject jsonObject = JSONObject.parseObject(str);
        JSONObject dataObject = jsonObject.getJSONObject("data");
        DouyinCouponPrepareResult douyinCouponPrepareResult = null;
        Integer errorCode = dataObject.getInteger("error_code");
        String verify_token = dataObject.getString("verify_token");
        String description = dataObject.getString("description");

        JSONArray certificatesArry = dataObject.getJSONArray("certificates");
        JSONObject certificates = certificatesArry.getJSONObject(0);

        String encrypted_code = certificates.getString("encrypted_code");
        Integer expire_time = certificates.getInteger("expire_time");
        JSONObject skuObject = certificates.getJSONObject("sku");
        String thirdSkuId = skuObject.getString("third_sku_id");

        if (errorCode == 0) {
            douyinCouponPrepareResult = new DouyinCouponPrepareResult();
            douyinCouponPrepareResult.setVerifyToken(verify_token);
            douyinCouponPrepareResult.setEncryptedCode(encrypted_code);
            douyinCouponPrepareResult.setThirdSkuId(thirdSkuId);
        }

        return douyinCouponPrepareResult;
    }

    public static void main(String[] args) {
        try {
            String url = "https://open.douyin.com/goodlife/v1/fulfilment/certificate/verify/";
            Map<String, String> param = new HashMap<String, String>();
            param.put("verify_token", "4b65e678-15ff-427d-bb36-cf88114900d1");
            param.put("poi_id", "7299654575076673573");
            List encrypted_codes = new ArrayList();
            encrypted_codes.add("CgwIARDhJxjLLyABKAESLgosuK+xzkwZle5e5mOxZXG2tcwVlINciXVfoGmaNG+9Fgv9kZW4vV3pdicu2LkaAA==");
            param.put("encrypted_codes", encrypted_codes.toString());
            String resultStr = "";
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS) // 超时设置
                    .writeTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(20, TimeUnit.SECONDS)
                    .build();
            Request.Builder requestBuilder = new Request.Builder();
            requestBuilder.addHeader("Content-Type", "application/json");
            requestBuilder.addHeader("access-token", "");
            FormBody.Builder builder = new FormBody.Builder();
            for (String key : param.keySet()) {
                log.info("log add key=" + key);
                builder.add(key, param.get(key));
            }
            Request request = requestBuilder.post(builder.build()).url(url).build();
            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
            resultStr = Objects.requireNonNull(response.body()).string();
            log.info("okhttp post请求结果. url：{} param：{} result:{}", url, param, resultStr);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 小程序端用户提交卡券兑换
     *
     * @param douyinConponParam
     * @return
     */
    @SneakyThrows
    @Override
    public DouyinCouponVerifyResult frontSubmitVerifyCoupon(DouyinConponParam douyinConponParam) {
        String clientToken = getClientToken(douyinConponParam.getStoreId());
        // 验券准备
        DouyinCouponPrepareResult prepareResult = prepareCertificate(douyinConponParam.getCode(),
                douyinConponParam.getEncryptedData(), clientToken);
        // 验券
        DouyinCouponVerifyResult verifyResult = verifyCoupon(douyinConponParam.getUserId(), douyinConponParam.getStoreId(),
                douyinConponParam.getPoiId(), prepareResult.getVerifyToken(),
                prepareResult.getEncryptedCode(), prepareResult.getThirdSkuId());

        return verifyResult;
    }

    @Override
    public DouyinCouponVerifyResult verifyCoupon(Integer userId, Integer storeId, String poiId, String verifyToken, String encryptedCode, String thirdSkuId) throws IOException {
        String url = "https://open.douyin.com/goodlife/v1/fulfilment/certificate/verify/";
        JSONObject param = new JSONObject();
        param.put("verify_token", verifyToken);
        param.put("poi_id", poiId);
        if (StringUtils.isEmpty(poiId)){
            MtStore mtStore = storeService.queryStoreById(storeId);
            param.put("poi_id", mtStore.getPoiId());
        }
        JSONArray encrypted_codes = new JSONArray();
        encrypted_codes.add(encryptedCode);
        param.put("encrypted_codes", encrypted_codes);
        String str = post1(url, storeId, param);
        JSONObject jsonStr = JSONObject.parseObject(str);
        JSONObject dataObject = (JSONObject) jsonStr.get("data");
        Integer errorCode = dataObject.getInteger("error_code");
        String description = dataObject.getString("description");
        DouyinCouponVerifyResult douyincCouponVerifyResult = null;
        List<VerifyResult> verifyResultList = new ArrayList<>();
        if (errorCode == 0) {
            // 根据本地的卡券或优惠券Id,生成一张用户卡券-thirdSkuId
            LambdaQueryWrapper<MtCoupon> lambdaQueryWrapper = Wrappers.lambdaQuery();
            lambdaQueryWrapper.eq(MtCoupon::getId, thirdSkuId);
            List<MtCoupon> dataList = mtCouponMapper.selectList(lambdaQueryWrapper);
            if (dataList != null) {
                MtCoupon mtCoupon = dataList.get(0);
                // 用户卡券(小时卡、次数卡)购买订单
                // 生成用户对应的卡券
                if (mtCoupon.getType().equals(CouponTypeEnum.HOUR.getKey())
                        || mtCoupon.getType().equals(CouponTypeEnum.NUMTIMES.getKey())) {
                    Map<String, Object> paramCoupon = new HashMap<>();
                    paramCoupon.put("couponId", mtCoupon.getId());
                    paramCoupon.put("userId", userId);
                    paramCoupon.put("orderId", poiId);
                    paramCoupon.put("storeId", storeId);
                    userCouponService.userBuyConpon(paramCoupon);
                    // 生成用户对应的优惠券
                } else if (mtCoupon.getType().equals(CouponTypeEnum.COUPON.getKey())) {
                    userCouponService.buyCouponItem(poiId, mtCoupon.getId(), userId, storeId,"D");
                }
            }
            JSONArray verifyResults = dataObject.getJSONArray("verify_results");
            douyincCouponVerifyResult = new DouyinCouponVerifyResult();
            for (int i = 0; i < verifyResults.size(); i++) {
                JSONObject obj = verifyResults.getJSONObject(i);
                VerifyResult verifyResult = new VerifyResult();
                verifyResult.setMsg(obj.getString("msg"));
                verifyResult.setCode(obj.getString("code"));
                verifyResult.setVerifyId(obj.getString("verify_id"));
                verifyResult.setCertificateId(obj.getString("certificate_id"));
                verifyResult.setOriginCode(obj.getString("origin_code"));
                verifyResult.setAccountId(obj.getString("account_id"));
                verifyResult.setResult(obj.getInteger("result"));
                verifyResultList.add(verifyResult);
            }
            douyincCouponVerifyResult.setVerifyResults(verifyResultList);
            douyincCouponVerifyResult.setErrorCode(errorCode);
            douyincCouponVerifyResult.setDescription(description);

        }
        return douyincCouponVerifyResult;
    }

    public String getDataSynFromNet(String code, String encryptedData, String clientToken) throws UnsupportedEncodingException {
        //创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS) // 超时设置
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        String url = "https://open.douyin.com/goodlife/v1/fulfilment/certificate/prepare/?code=" + code;
        if (!StringUtils.isEmpty(encryptedData)) {
            // URLEncoder.encode(encryptedData, "UTF-8");
            encryptedData = URLEncoder.encode(encryptedData, "UTF-8");
            url = "https://open.douyin.com/goodlife/v1/fulfilment/certificate/prepare/?encrypted_data=" + encryptedData;
        }
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Content-Type", "application/json")
                .addHeader("access-token", clientToken)
                .get()
                .build();
        //2 将Request封装为Call
        Call call = okHttpClient.newCall(request);
        //3 执行Call，得到response
        Response response = null;
        String jsonStr = "";
        try {
            response = call.execute();
            jsonStr = response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonStr;
    }

    public String post1(String url, Integer storeId, JSONObject param) throws IOException {
        String resultStr = "";
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS) // 超时设置
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.addHeader("Content-Type", "application/json");
        requestBuilder.addHeader("access-token", getClientToken(storeId));
        Request request = requestBuilder.post(RequestBody.create(MediaType.parse("application/json"), param.toJSONString())).url(url).build();
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        resultStr = Objects.requireNonNull(response.body()).string();
        log.info("okhttp post请求结果. url：{} param：{} result:{}", url, param, resultStr);
        return resultStr;
    }

    public void get(String url, String client_token, Map<String, String> param) throws IOException {
        //创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS) // 超时设置
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        final Request request = new Request.Builder()
                .url("http://XXXX.com")
                .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36")
                .addHeader("Host", "XXXX.com")
                .get()
                .build();

        Call call = okHttpClient.newCall(request);
        //异步操作
        call.enqueue(new Callback() {
            //请求错误回调方法
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("连接失败");
            }

            //异步请求(非主线程)
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.code() == 200) {
                    System.out.println(response.body().string());
                }
            }
        });
    }

}
